package com.whu;

import javafx.geometry.Point2D;
import javafx.scene.Parent;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.transform.Affine;
import javafx.scene.transform.NonInvertibleTransformException;

public class MainView extends VBox {

    private Canvas canvas;
    private Infobar infobar;


    public static final int EDITING = 0;
    public static final int SIMULATING = 1;
    private int applicationState = EDITING;


    // 映射工具，缩放比例。重新排列显示
    private Affine affine;

    private Simulation simulation;
    private Simulation initSimulation;
    private Simulator simulator;

    private int drawMode = Simulation.ALIVE;// 绘画方式 1 表示画alive 0 表示画dead

    // 初始化面板
    public MainView() {
        this.canvas = new Canvas(400, 400);
        this.canvas.setOnMousePressed(this::handlerDraw); // 点击
        this.canvas.setOnMouseDragged(this::handlerDraw);
        this.canvas.setOnMouseMoved(this::handlerMove);

        // 按键监听
        this.setOnKeyPressed(this::onKeyPress);

        Toolbar toolbar = new Toolbar(this);

        this.infobar = new Infobar();
        this.infobar.setDrawMode(this.drawMode);
        this.infobar.setCursorPos(0, 0);


        Pane spacer = new Pane();// 创建一个小面板，放infobar
        spacer.setMinSize(0, 0);
        spacer.setMaxSize(Double.MAX_VALUE, Double.MIN_VALUE);
        VBox.setVgrow(spacer, Priority.ALWAYS);

        //添加画布和按钮到面板
        this.getChildren().addAll(toolbar,spacer, this.canvas, infobar);

        this.affine = new Affine();
        // 缩放
        this.affine.appendScale(400 / 30f, 400 / 30f);
        this.initSimulation = new Simulation(300,300);
        this.simulation = Simulation.copy(this.initSimulation);
    }

    // 鼠标移动监听事件
    private void handlerMove(MouseEvent mouseEvent) {
        Point2D simCoord = getSimulationCoordinates(mouseEvent);
        int simX = (int) simCoord.getX();
        int simY = (int) simCoord.getY();
        this.infobar.setCursorPos(simX, simY);
    }

    // 坐标转换工具类
    public Point2D getSimulationCoordinates(MouseEvent mouseEvent){
        double mouseX = mouseEvent.getX();
        double mouseY = mouseEvent.getY();
        Point2D simCoord = null;
        try {
            // 缩表映射, mouseEvent获得的是board的坐标，需要转化为当前的画布坐标
            simCoord = this.affine.inverseTransform(mouseX, mouseY);
        }catch (Exception e){
            System.out.println("无法转换");
        }
        return simCoord;
    }

    // 按键事件, 切换点击状态
    private void onKeyPress(KeyEvent keyEvent) {
        if(keyEvent.getCode() == KeyCode.D){
            this.drawMode = Simulation.ALIVE;
        }else if(keyEvent.getCode() == KeyCode.E){
            this.drawMode = Simulation.DEAD;
        }
    }

    // 点击画布，自动设置当前点为alive
    private void handlerDraw(MouseEvent mouseEvent) {
        if(this.applicationState == SIMULATING){
            return;
        }
        Point2D simCoord = getSimulationCoordinates(mouseEvent);
        int simX = (int) simCoord.getX();
        int simY = (int) simCoord.getY();

        // 0 就表示设置dead，1就表示设置alive
        this.initSimulation.setState(simX, simY, drawMode);
        draw();// 重置画布
    }

    public void draw(){
        GraphicsContext g = this.canvas.getGraphicsContext2D();
        g.setFill(Color.LIGHTGRAY);
        g.setTransform(this.affine);
        g.fillRect(0,0,450,450);

        if(this.applicationState == EDITING){
            drawSimupaltion(this.initSimulation);
        }else{
            drawSimupaltion(this.simulation);
        }

        g.setStroke(Color.GRAY);
        g.setLineWidth(0.05f);
        for (int i = 0; i <= this.simulation.width; i++) {
            g.strokeLine(i, 0, i, 30);
        }
        for (int j = 0; j <= this.simulation.height; j++) {
            g.strokeLine(0, j, 30, j);
        }
    }

    public Simulation getSimulation() {
        return this.simulation;
    }

    private void drawSimupaltion(Simulation simulationToDraw){
        GraphicsContext g = this.canvas.getGraphicsContext2D();
        g.setFill(Color.BLACK);
        for (int i = 0; i < simulationToDraw.width; i++) {
            for (int j = 0; j < simulationToDraw.height; j++) {
                if(simulationToDraw.getState(i,j) == Simulation.ALIVE){ // Alive 就填充为黑色
                    g.fillRect(i, j,1,1);
                }
            }
        }
    }

    public void setDrawMode(int newDrawMode) {
        this.drawMode = newDrawMode;
        this.infobar.setDrawMode(newDrawMode);
    }

    public void setApplicationState(int applicationState) {
        if(applicationState == this.applicationState){
            return;
        }

        if(applicationState == SIMULATING) { // 模拟状态下，就新建一个副本
            this.simulation = Simulation.copy(this.initSimulation);
            this.simulator = new Simulator(this, this.simulation);
        }


        this.applicationState = applicationState;
    }

    public Simulator getSimulator() {
        return simulator;
    }
}
